from rest_framework import serializers
from book.models import HeroInfo, BookInfo


class HeroInfoSerialzier(serializers.Serializer):
    """
        英雄表的序列化器
    """
    hname = serializers.CharField()
    hgender = serializers.IntegerField()
    hcomment = serializers.CharField()


# 自定以序列化器类，完成序列化和反序列化的方法指定
class BookInfoSerialzier(serializers.Serializer):
    """
        序列化器是对那个模型类资源操作，定义名字是使用该模型类名+后缀Serialzier。不是强制要求，命名任意名字也可以
    """
    # 指定序列化返回字段，可以根据对应的模型类指定字段,区别在于models和serializer

    # read_only的作用，只参与序列化过程，不参与反序列化（验证）
    # write_only作用，只参与反序列化过程，不参与序列化
    # label 用于HTML展示API页面时，显示的字段名称
    id = serializers.IntegerField(label='ID', read_only=True)

    # 反序列化验证时，可以指定选项参数进行验证
    btitle = serializers.CharField(max_length=20,min_length=2)
    bpub_date = serializers.DateField()
    # bread = serializers.IntegerField(max_value=100, min_value=0)

    # default反序列化时使用的默认值
    bread = serializers.IntegerField(default=0)
    bcomment = serializers.IntegerField()

    # 嵌套序列化返回 例如：返回图书信息时，将图书对应的英雄信息一并返回
    # 指定嵌套字段 主表嵌套副表返回，使用副表表名的小写_set
    # 返回形式有三种:
    # 第一种返回关联表的id,一本图书对应多个英雄,所以需要用到many=True
    # PrimaryKeyRelatedField此字段将被序列化为关联对象的主键
    # heroinfo_set = serializers.PrimaryKeyRelatedField(many=True, queryset=HeroInfo.objects.all())

    # 第二种返回关联表中的str方法的结果,一本图书对应多个英雄，所以需要用到many=True
    # StringRelatedField
    # 此字段将被序列化为关联对象的字符串表示方式（即__str__方法的返回值）
    # heroinfo_set = serializers.StringRelatedField(many=True)

    # 返回形式有三种，第三种定义关联表的序列化进行指定,一本图书对应多个英雄，所以需要用到many=True
    # heroinfo_set = HeroInfoSerialzier(many=True)

    # 验证图书书名不能为python
    # 方法验证:第一种单一字段验证，第二种：多个字段验证
    def validate_btitle(self, attrs):
        """
        单一字段验证，书写形式validate_验证的字段名
        :param attrs: 字段所以对应的数据
        :return:
        """

        if attrs == "python":
            # 判断书名为python，验证失败，抛出异常，异常信息被视图中的ser.errors获取
            raise serializers.ValidationError('图书书名不能为python')
        # 验证通过，要返回验证结果
        return attrs

    # 多个字段验证方法  阅读量大于评论量
    def validate(self, attrs):
        """

        :param attrs: 接受所有的验证字段，字典
        :return:
        """
        # 从attrs中取出对应的字段数据进行判断
        # 实际场景 比较两次密码是否一直
        if attrs['bread'] > attrs['bcomment']:
            # 验证不通过，抛出异常
            raise serializers.ValidationError('阅读量大于评论量')
        # 验证通过返回验证数据结果
        return attrs

    # 保存方法
    def create(self, validated_data):
        """
            将保存数据库的业务,在该方法中封装
        :param validated_data:接收验证后的数据
        :return:
        """
        book = BookInfo.objects.create(**validated_data)

        # 保存成功后返回保存对象，方便下一步的序列化返回
        return book

    # 更新方法
    def update(self, instance, validated_data):
        """

        :param instance: 更新的数据对象
        :param validated_data: 验证后的数据
        :return:
        """
        res = BookInfo.objects.filter(id=instance.id).update(**validated_data)

        if res == 0:
            raise serializers.ValidationError('更新失败')

        book = BookInfo.objects.get(id=instance.id)

        return book
